        TITL DAI FIRMWARE C000-C1FA  V1.0  Rev.1
        ORG   :C000
*
*
*
*  =================
*** MATH. UTILITIES ***
*  =================
*
*
***************
* ENTRYPOINTS *
***************
*
BASE    JMP   :C719     Reset (entry on hardware
 REM reset)
XINIT   JMP   :C035     Math. package initialisation
XFINM   JMP   :C0F3     Incr. FPT number in memory
XFDCM   JMP   :C1FB     Decr. FPT number in memory
 REM (not used)
XFCOMP  JMP   :C079     FPT Compare
XIINM   JMP   :C0BB     Incr. INT number in memory
XIDCM   JMP   :C0D5     Decr. INT number in memory
 REM (not used)
XICOMP  JMP   :C0AC     INT Compare
XPUSH   JMP   :C21E     Save MACC on stack
XPOP    JMP   :C234     Retrieve MACC from stack
XFCB    JMP   :C249     Input FPT number to MACC
XFBC    JMP   :C361     Conv. FPT number for output
XICB    JMP   :C573     Input INT number to MACC
XIBC    JMP   :C5B2     Conv. INT number for output
XHCB    JMP   :C614     Input Hex number to MACC
XHBC    JMP   :C653     Conv. MACC to Hex for output
XPRTY   JMP   :C486     Pretties up FPT/INT number
DECBUF  DBL   :00E3     Location output buffer
*
********************************
* MATH. PACKAGE INITIALISATION *
********************************
*
* Entry: HL: Address input encoding routine (DDE0).
*        DE: Base address error routines (C7F2).
* Exit:  AFDEHL corrupted, BC preserved.
*
MINIT   SHLD  :00D2     Init. (00D2/3)=DDE0
        XCHG
        SHLD  :00D0     Init. (00D0/1)=C7F2
        LDA   :FB02     Get math.chip status
        ORA   A         Check if math.chip present
        MVI   A,:00     Flag = 0 if not
        JM    :C047
        MVI   A,:7B     Flag = #7B if present
LC18    STA   :00D4     Set math.chip flag
        RET
*
**************************
* OVERFLOW ERROR ROUTINE *
**************************
*
* (From LC20 common part for various entries).
*
* Jump to (00D0/1) = Address 'overflow error'
* routine (C7F2).
*
* Entry: If start at LC20: offset in HL.
* Exit:  AFBCDEHL preserved.
*        On stack original returnaddress.
*
FPEOV   PUSH  H
        LXI   H,:0000   Init offset = 0
*
LC20    PUSH  PSW
        PUSH  D
        XCHG            Offset in DE
        LHLD  :00D0     Get addr pointer
        DAD   D         Add offset
        MOV   A,M
        INX   H
        MOV   H,M
        MOV   L,A       Get addr routine in HL
        POP   D
        POP   PSW
        XTHL            New addr on stack
        RET             Continu with new address
*
******************
* ARGUMENT ERROR *
******************
*
* Jump to (00D0/1)+2 = Address 'number out of range'
* routine (C7F4).
*
* Entry/exit: See FPEOV.
*
FPEAE   PUSH  H
        LXI   H,:0002   Init. offset
        JMP   :C04F     Calc. new addr, go to it
*
*******************
* UNDERFLOW ERROR *
*******************
*
* Jump to (00D0/1)+4 = Return (C7F6).
* Underflow gives 0 as result of operation.
*
* Entry/exit: See FPEOV.
*
FPEUN   PUSH  H
        LXI   H,:C45E   Addr. FPT(0)
        JMP   :D20C     Copy '0' into MACC
*
************************
* DIVIDE BY ZERO ERROR *
************************
*
* Jump to (00D0/1)+6 = Address 'divide by zero'
* routine (C7F8).
*
* Entry/exit: See FPEOV.
*
FPED0   PUSH  H
        LXI   H,:0006   Init. offset
        JMP   :C04F     Calc. new addr, go to it
*
*
***************************
* GET CHARACTER FROM LINE *
***************************
*
* Entry: None.
* Exit : All registers preserved.
*        Address to continue on stack.
*
LC22    PUSH  H
        LHLD  :00D2     Get addr 'Get char' routine
        XTHL            on stack; restore HL
        RET             Goto (00D0/1)+2
*
**************************
* FLOATING POINT COMPARE *
**************************
*
* Compares normalised FPT numbers in MACC
* and in M.
*
* Exit: ABCDEHL preserved.
*       Flags: CY=1,S=0,Z=1: both nrs. 0
*              CY=0,S=0,Z=1: both nrs. identical
*              CY=0,S=0,Z=0: MACC > M
*              CY=0,S=1,Z=0: MACC < M
*
FCOMP   PUSH  B
        PUSH  PSW
        PUSH  D
        PUSH  H
        RST   4         Copy MACC to reg A,B,C,D
        DATA  :15
        MOV   E,A       Exp.byte in E
        XRA   M         XOR both exp.bytes
        JM    :C0B7     Jump if different signs
 REM
* If equal signs:
 REM
        JMP   :D1E8     Goto D1E8, return to C087
*
LC23    RAL
        JNZ   :C0A3
LC24    MOV   A,E
        SUB   M         Comp. exp. bytes
        JNZ   :C0A2     Jump if not equal
        INX   H
        MOV   A,B
        SUB   M         Comp. 1st bytes mantissa's
        JNZ   :C0A2     Jump if not equal
        INX   H
        MOV   A,C
        SUB   M         Comp. 2nd bytes mantissa's
        JNZ   :C0A2     Jump if not equal
        INX   H
        MOV   A,D
        SUB   M         Comp. 3rd bytes mantissa's
LC25    JZ    :C0A6     Jump if not equal
LC26    RAR             ) Set flags for output
LC27    XRA   E         )
LC28    ORI   :01       Clear CY-flag
LC29    POP   H
        POP   D
        POP   B
        MOV   A,B       Restore A
        POP   B
        RET
*
*******************
* INTEGER COMPARE *
*******************
*
* Compares INT numbers in MACC and M.
* REMARK: Routine is incorrect when both
*         numbers are negative ! Then result
*         is if MACC > M due to LC26/LC27.
*
* Exit:  ABCDEHL preserved. CY=0
*        Flags: S=0, Z=1: Both numbers equal
*               S=0, Z=0: MACC > M
*               S=1, Z=0: MACC < M
*
ICOMP   PUSH  B
        PUSH  PSW
        PUSH  D
        PUSH  H
        RST   4         Copy MACC to reg. A,B,C,D
        DATA  :15
        MOV   E,A       Sign byte in E
        XRA   M         XOR both sign bytes
        JP    :C08B     If both nrs have same sign:
 REM compare
 REM
* If different signs:
 REM
LC241   XRA   M         Find out which one is neg:
 REM S=1: MEM pos; MACC neg
 REM S=0: MEM neg; MACC pos
        JMP   :C0A4     Abort
*
**************************************
* INCREMENT INTEGER NUMBER IN MEMORY *
**************************************
*
* Entry: HL points to 1st byte of INT number.
* Exit:  All registers preserved.
*
IINM    PUSH  PSW
        PUSH  H
        INX   H
        INX   H
        INX   H         HL pnts to last byte
        MVI   A,:03     Nr of bytes for INT nr
LC30    INR   M         Incr. INT nr.
        JNZ   :C0D2     Ready if no overflow
        DCX   H         Goto next byte
        DCR   A         1st byte reached?
        JNZ   :C0C2     Incr. next byte
        INR   M         Incr. 1st byte
        MOV   A,M       Get it
        CPI   :80       msb=1?
        CZ    :C04B     Then overflow error
LC31    POP   H         Normal return
        POP   PSW
        RET
*
***************************************************
* DECREMENT INTEGER NUMBER IN MEMORY - (not used) *
***************************************************
*
* Entry: HL points to 1st byte of INT number.
* Exit:  All registers preserved.
*
IDCM    PUSH  PSW
        PUSH  B
        PUSH  H
        INX   H
        INX   H
        INX   H         HL pnts to last byte
        MVI   B,:03     Nr. of bytes of INT nr.
LC32    DCR   M         Decr. INT nr
        MOV   A,M
        INR   A         Check for overflow
        JNZ   :C0EF     Ready if no overflow
        DCX   H         Goto next byte
        DCR   B         Decr. byte count
        JNZ   :C0DD     Next byte if not ready
        DCR   M         Decr. hibyte
        MOV   A,M
        CPI   :7F       Check for overflow
        CZ    :C04B     Then run overflow error
LC33    POP   H         Normal return
        POP   B
        POP   PSW
        RET
*
*********************************************
* INCREMENT FLOATING POINT NUMBER IN MEMORY *
*********************************************
*
* If number = 0, or exponent < 0, a '1' is added
* to the lsb of the mantissa. Else, the position
* of the least significant '1' is looked up, and
* a '1' is added to this position.
* If the lsb of the mantissa is already a rounded
* value, no increment occurs.
*
* Entry: HL points to 1st byte of FPT number.
* Exit:  All registers preserved.
*
FINM    PUSH  PSW
        PUSH  B
        PUSH  D
        PUSH  H
        LXI   D,:C462   Addr FPT(1)
        MOV   A,M       Get exp.byte
        ANI   :7F       Mask sign bit
        JZ    :C1AC     If nr=0: add 1, abort
        CPI   :40       Is exponent negative?
        JNC   :C1AC     Then add 1, abort
        CPI   :19       Lsb of mantissa is not lsb
 REM of number ?
        JNC   :C14D     Then Popall, ret
        CMP   M         Check if nr. is negative
        INX   H
        JNZ   :C152     Then jump
 REM
* From LC34 also used by XFDCM.
* Find lsb of mantissa if nr is positive:
 REM
LC34    SUI   :09       In 1st byte ?
        CC    :C1EE     Then SHL bit into A (A) time
        JC    :C136     and jump
        INX   H
        SUI   :08       In 2nd byte ?
        CC    :C1EE     Then SHL bit into A (A) time
        JC    :C12E     and jump
        INX   H
        SUI   :08       In 3rd byte ?
        CALL  :C1EE     Then SHL bit into A (A) time
        ADD   M
        MOV   M,A       Add 1 to 3rd byte mantissa
        JNC   :C14D     Ready if no overflow
        DCX   H
        MVI   A,:01     Overflow: add 1 to 2nd byte
LC35    ADD   M
        MOV   M,A       Add 1 to 2nd byte mantissa
        JNC   :C14D     Ready if no overflow
        DCX   H
        MVI   A,:01     Overflow: add 1 to 1st byte
LC36    ADD   M
        MOV   M,A       Add 1 to 1st byte mantissa
        JNC   :C14D     Ready if no overflow
 REM
* If overflow into exponent byte:
 REM
        RAR             )
        MOV   M,A       )
        INX   H         )
        MOV   A,M       ) Shift all bits in
        RAR             ) mantissa right
        MOV   M,A       ) one position
        INX   H         )
        MOV   A,M       )
        RAR             )
        MOV   M,A       )
        DCX   H
        DCX   H
        DCX   H         HL pnts to exp.byte
        MVI   A,:01
LC37    CALL  :C1BA     Add 1 to exponent
*
EXIT    POP   H
        POP   D
        POP   B
        POP   PSW
        RET
 REM
* Find lsb of mantissa if nr is negative:
 REM
LC39    SUI   :09       In 1st byte ?
        CC    :C1EE     Then SHL bit into A (A) time
        JC    :C17D     and jump
        INX   H
        SUI   :08       In 2nd byte ?
        CC    :C1EE     Then SHL bit into A (A) time
        JC    :C173     and jump
        INX   H
        SUI   :08       In 3rd byte ?
        CC    :C1EE     Then SHL bit into A (A) time
        MOV   B,A
        MOV   A,M
        SUB   B         Subtract 1 from 3rd byte
        MOV   M,A
        JNC   :C14D     Ready if no borrow
        DCX   H
        MVI   A,:01     Subtract 1 from 2nd byte if
 REM borrow
LC40    MOV   B,A
        MOV   A,M
        SUB   B         Subtract 1 from 2nd byte
        MOV   M,A
        JNC   :C14D     Ready if no borrow
        DCX   H
        MVI   A,:01     Subtract 1 from 1st byte if
 REM borrow
LC41    MOV   B,A
        MOV   A,M
        SUB   B         Subtract 1 from 1st byte
        MOV   M,A
        JM    :C14D     Ready if normalised
 REM
* If not normalised:
 REM
        MVI   B,:18     Nr of mantissa bits
LC42    INX   H         )
        INX   H         )
        ORA   A         )
        MOV   A,M       )
        RAL             )
        MOV   M,A       ) Shift all bits
        DCX   H         ) of mantissa
        MOV   A,M       ) left one position
        RAL             )
        MOV   M,A       )
        DCX   H         )
        MOV   A,M       )
        RAL             )
        MOV   M,A       )
        ORA   A
        JM    :C19F     If normalized
        DCR   B         Update exp. count
        JZ    :C1A6     If exp. now zero
        JMP   :C186     Cont. normalisation
 REM
* Normalisation done:
 REM
LC43    DCX   H         Pnts to exp.byte
        MOV   A,B       Get exp. count
        SUI   :19       Minus nr of bytes in
 REM mantissa
        JMP   :C14A     Update exponent, quit
 REM
* If exponent is zero:
 REM
LC44    DCX   H
        MVI   M,:00     Exp.byte is 0
        JMP   :C14D     Popall, ret
 REM
* Simply add 1 (FINM) or add -1 (FDCM):
 REM
LC45    RST   4         Copy number into MACC
        DATA  :0C
        XCHG
        RST   4         Add 1 or -1 (FPT)
        DATA  :00
        XCHG
        RST   4         Copy MACC into memory
        DATA  :0F
        JMP   :C14D     Popall, ret
*
*****************
* ADD EXPONENTS *
*****************
*
* LC225 for operand in MACC.
* LC46 for operand in M.
*
* Entry: Byte to be added to exponent in A.
* Exit:  BCDEHL preserved.
*        CY=0: O.K.
*        CY=1: Overflow.
*
LC225   LXI   H,:00D5   Addr. MACC
*
LC46    PUSH  H
        PUSH  D
        PUSH  B
        MOV   C,A       Byte to be added in C
        MOV   A,M       Get exp.byte operand
        ANI   :80       Sign bit mantissa only
        MOV   B,A       in B
        MOV   A,M       Get exp.byte
        CALL  :C1E9     Sign extend
        PUSH  PSW       Save sign extended exp.byte
        XRA   C         XOR with byte to be added
        CMA
        MOV   D,A
        POP   PSW       Get sign extended exp.byte
        ADD   C         Add byte to exponent
        MOV   C,A       Store result
        RAR
        XRA   C
        ANA   D
        JM    :C1E2     If overflow into sign bit
        MOV   A,C       Get new exp.byte
        RAL
        XRA   C
        JM    :C1E2     If overflow into sign bit
        MOV   A,C       Get new exp.byte
        ANI   :7F       Exponent only
        ORA   B         Add sign bit mantissa
        MOV   M,A       Store it
LC47    POP   B
        POP   D
        POP   H
        RET             CY=0
 REM
* If overflow into sign bit:
 REM
LC48    MOV   A,C       Get new exp.byte
        RAL
        ORA   A
        STC
        JMP   :C1DE     Abort with CY=1
*
***************
* SIGN EXTEND *
***************
*
* Exponent byte is normalized.
*
* Entry: Exp.byte in A.
* Exit:  BCDEHL preserved.
*        Normalized exp.byte in A: Exp.value in
*        bits 7-2, sign mantissa in bit 1, sign
*        exponent in bit 0.
*
SEXT    RLC
        RLC
        RRC
        RAR
        RET
*
************************************
* MOVE A BIT INTO A LEFT (A) TIMES *
************************************
*
* Used to place a '1' in the correct position in
* a byte for adding/subtracting '1' to/from the
* least significant '1' of a FPT mantissa.
*
* Entry: A contains a neg. number indicating
*        how often RAL has to be performed.
* Exit:  Result in A,B.
*        FCDEHL preserved.
*
LC50    PUSH  PSW
        MOV   B,A       Save nr of shifts
        XRA   A         Clear A
        STC             Set CY
LC51    RAL             SHL
        INR   B         Update count
        JNZ   :C1F2     Continu if not ready
        MOV   B,A       Save result
        POP   PSW
        MOV   A,B       Result in A
        RET
*
*
*
        END
